package service

import (
	"context"
	"fmt"

	"database/sql"

	dbmodel "gitee.com/hp-huiw/family-expense-api/internal/db/model"
	"gitee.com/hp-huiw/family-expense-api/internal/dto"
	"gitee.com/hp-huiw/family-expense-api/internal/repository"
	"github.com/samber/lo"

	"gitee.com/hp-huiw/my-go-core/config"
	"gitee.com/hp-huiw/my-go-core/date"
	"gitee.com/hp-huiw/my-go-core/util"
)

type AppReleaseLogService interface {
	Initialize(ctx context.Context) error
	QueryByAppVersion(ctx context.Context, appVersion string) (*dto.AppReleaseLogResponse, error)
	QueryLatestVersion(ctx context.Context, appVersion string) (*dto.AppReleaseLogResponse, error)
	ListChangeLog(ctx context.Context, pageSize int64, pageIndex int64) ([]dto.AppReleaseLogResponse, error)
}

// NewAppReleaseLogService creates a new instance of AppReleaseLogService.
func NewAppReleaseLogService(db *sql.DB) AppReleaseLogService {
	return &appReleaseLogService{
		appConfig:               config.ConfigLoader.GetAppConfig(),
		db:                      db,
		appReleaseLogRepository: repository.NewAppReleaseLogRepository(db),
	}
}

// Initialize prepares the initial data for AppReleaseLog.
func (s *appReleaseLogService) Initialize(ctx context.Context) error {
	exists, err := s.appReleaseLogRepository.Exists(ctx)

	if err != nil {
		return err
	}

	if !exists {
		releaseDate, _ := date.ParseDateInDefaultLocation(2021, 10, 1)

		item := dbmodel.AppReleaseLog{
			ID:          util.GenerateUUIDWithoutDashes(),
			ReleaseDate: releaseDate,
			AppVersion:  "1.0.0",
			ChangeLog:   "初始版本",
			ApkFilename: "family-expense.apk",
			AppStoreURL: "https://",
			IsMandatory: false,
		}

		err = s.appReleaseLogRepository.Insert(ctx, &item)
	}

	return err
}

// QueryByAppVersion queries the app release details by its version.
func (s *appReleaseLogService) QueryByAppVersion(ctx context.Context, appVersion string) (*dto.AppReleaseLogResponse, error) {
	query, err := s.appReleaseLogRepository.QueryByAppVersion(ctx, appVersion)

	if err != nil {
		return nil, err
	}

	if query != nil {
		result := &dto.AppReleaseLogResponse{
			AppVersion:  query.AppVersion,
			ReleaseDate: query.ReleaseDate,
			ApkUrl:      util.AnyPtr(fmt.Sprintf("%v/%v/%v", s.appConfig.Resource.HttpBaseUrl, s.appConfig.Resource.ApkDirectoryName, query.ApkFilename)),
			IsMandatory: query.IsMandatory,
		}

		return result, nil
	}

	return nil, nil
}

// QueryLatestVersion queries the latest version which released after the provided releaseDate.
func (s *appReleaseLogService) QueryLatestVersion(ctx context.Context, appVersion string) (*dto.AppReleaseLogResponse, error) {
	mandatoryExists, err := s.appReleaseLogRepository.MandatoryExists(ctx, appVersion)

	if err != nil {
		return nil, err
	}

	query, err := s.appReleaseLogRepository.QueryLatestVersion(ctx, appVersion)

	if err != nil {
		return nil, err
	}

	if query != nil {
		result := &dto.AppReleaseLogResponse{
			AppVersion:  query.AppVersion,
			ReleaseDate: query.ReleaseDate,
			ApkUrl:      util.AnyPtr(fmt.Sprintf("%v/%v/%v", s.appConfig.Resource.HttpBaseUrl, s.appConfig.Resource.ApkDirectoryName, query.ApkFilename)),
			IsMandatory: mandatoryExists,
			ApkFilename: &query.ApkFilename,
			ChangeLog:   &query.ChangeLog,
		}

		return result, nil
	}

	return nil, nil
}

// ListChangeLog lists change log info.
func (s *appReleaseLogService) ListChangeLog(ctx context.Context, pageSize int64, pageIndex int64) ([]dto.AppReleaseLogResponse, error) {
	query, err := s.appReleaseLogRepository.ListChangeLog(ctx, pageSize, pageIndex)

	if err != nil {
		return nil, err
	}

	result := lo.Map(query, func(item repository.AppReleaseLog, _ int) dto.AppReleaseLogResponse {
		return dto.AppReleaseLogResponse{
			ID:          &item.ID,
			AppVersion:  item.AppVersion,
			ReleaseDate: item.ReleaseDate,
			ChangeLog:   &item.ChangeLog,
			IsMandatory: item.IsMandatory,
		}
	})

	return result, nil
}

// Container of AppReleaseLogService functions.
type appReleaseLogService struct {
	appConfig               config.AppConfig
	db                      *sql.DB
	appReleaseLogRepository repository.AppReleaseLogRepository
}
